package projet_v1.simulation;

import static org.junit.Assert.*;

import java.util.Iterator;
import java.util.Map.Entry;

import org.junit.Before;
import org.junit.Test;
import projet_v1.Breed;
import projet_v1.Character;
import projet_v1.Human;
import projet_v1.Vampire;
import projet_v1.simulation.events.ChimicalAttack;
import projet_v1.simulation.events.Event;
import projet_v1.simulation.events.Rescue;

/**
 * Test class for the Simulator class.
 * 
 * @author Antoine Lavail
 * 
 */
public class TestSimulator {

    private Simulator sim1;
    private Simulator sim2;

    /**
     * @throws java.lang.Exception
     */
    @Before
    public void setUp() throws Exception {
        sim1 = new Simulator();
        sim2 = new Simulator(10, 10);
    }

    /**
     * Test method for {@link projet_v1.simulation.Simulator#simulate(int)}.
     */
    @Test
    public void testSimulate() {
        Simulator s = new Simulator(3, 1);
        int sizeBefore = s.getCharacters().size();
        s.simulate(1);
        // The field isn't viable
        assertEquals(sizeBefore, s.getCharacters().size());
    }

    /**
     * Test method for {@link projet_v1.simulation.Simulator#simulateOneStep()}.
     */
    @Test
    public void testSimulateOneStep() {

        // Verify the step
        assertEquals(0, sim1.getStep());

        // Verify the characters.
        assertFalse(sim1.getCharacters().isEmpty());
        int nbChar = sim1.getCharacters().size();

        // Launch the simulateOneStep method.
        sim1.simulateOneStep();

        // Verify the changed number of characters.
        assertTrue(nbChar != sim1.getCharacters().size());

        // Verify the increment of the step.
        assertEquals(1, sim1.getStep());

        // The nextTurn method is also called in SimulateOneStep. The
        // correspondent test is located in testNextTurn() method.
    }

    /**
     * Test method for {@link projet_v1.simulation.Simulator#reset()}.
     */
    @Test
    public void testReset() {
        sim1.simulate(10);
        assertEquals(10, sim1.getStep());
        int sizeBefore = sim1.getCharacters().size();
        assertFalse(sim1.getCharacters().isEmpty());

        sim1.reset();
        assertEquals(0, sim1.getStep());
        assertFalse(sim1.getCharacters().isEmpty());
        assertNotSame(sizeBefore, sim1.getCharacters().size());
    }

    /**
     * Test method for {@link projet_v1.simulation.Simulator#nextTurn()}.
     */
    @Test
    public void testNextTurn() {
        sim2.simulateOneStep();
        assertFalse(sim2.getCharacters().isEmpty());
        for (int i = 0; i < sim2.getCharacters().size(); i++) {
            projet_v1.Character c = sim2.getCharacters().get(i);
            if (c.getBreed().equals(Breed.HUMAN)) {
                assertEquals(1, ((Human) c).getTurnsSinceLastMeal());
                sim2.nextTurn();
                assertEquals(2, ((Human) c).getTurnsSinceLastMeal());
                break;
            }
            if (c.getBreed().equals(Breed.VAMPIRE)) {
                assertEquals(1, ((Vampire) c).getDaysThirsty());
                sim2.nextTurn();
                assertEquals(2, ((Vampire) c).getDaysThirsty());
                break;
            }
        }
    }

    /**
     * Test method for
     * {@link projet_v1.simulation.Simulator#configureLocation(projet_v1.simulation.events.Event)}
     * .
     */
    @Test
    public void testConfigureLocation() {
        Simulator s = new Simulator(70, 70);
        s.simulate(10);

        Event event = s.getEvents().entrySet().iterator().next().getKey();
        Location oldLoc = event.getStartLocation();
        s.configureLocation(event);
        assertTrue(oldLoc != event.getStartLocation());
        oldLoc = event.getStartLocation();
        s.configureLocation(event);
        assertEquals(oldLoc, event.getStartLocation());

    }

    /**
     * Test method for {@link projet_v1.simulation.Simulator#nbHumansAlive()}.
     */
    @Test
    public void testNbHumansAlive() {
        sim1.simulate(2);

        int nbHumans = sim1.nbHumansAlive();
        sim1.simulate(10);
        assertTrue(nbHumans != sim1.nbHumansAlive());

    }

    /**
     * Test method for {@link projet_v1.simulation.Simulator#nbVampiresAlive()}.
     */
    @Test
    public void testNbVampiresAlive() {
        sim1.simulate(2);

        int nbVampire = sim1.nbVampiresAlive();
        sim1.simulate(10);
        assertTrue(nbVampire != sim1.nbVampiresAlive());
    }

    /**
     * Test method for {@link projet_v1.simulation.Simulator#nbZombiesAlive()}.
     */
    @Test
    public void testNbZombiesAlive() {
        sim1.simulate(2);

        int nbZombie = sim1.nbZombiesAlive();
        sim1.simulate(10);
        assertTrue(nbZombie != sim1.nbZombiesAlive());
    }
}
